home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / pico / word.c < prev   
C/C++ Source or Header  |  1996-05-14  |  20KB  |  659 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: word.c,v 4.23 1996/05/15 00:38:41 mikes Exp $";
  3. #endif
  4. /*
  5.  * Program:    Word at a time routines
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  *
  19.  * Pine and Pico are registered trademarks of the University of Washington.
  20.  * No commercial use of these trademarks may be made without prior written
  21.  * permission of the University of Washington.
  22.  * 
  23.  * Pine, Pico, and Pilot software and its included text are Copyright
  24.  * 1989-1996 by the University of Washington.
  25.  * 
  26.  * The full text of our legal notices is contained in the file called
  27.  * CPYRIGHT, included with this distribution.
  28.  *
  29.  */
  30. /*
  31.  * The routines in this file implement commands that work word at a time.
  32.  * There are all sorts of word mode commands. If I do any sentence and/or
  33.  * paragraph mode commands, they are likely to be put in this file.
  34.  */
  35.  
  36. #include        <stdio.h>
  37. #include    "osdep.h"
  38. #include        "pico.h"
  39. #include        "estruct.h"
  40. #include        <ctype.h>
  41. #include    "edef.h"
  42.  
  43.  
  44. /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
  45.  * line and stop on the first word-break or the beginning of the line. If we
  46.  * reach the beginning of the line, jump back to the end of the word and start
  47.  * a new line.  Otherwise, break the line at the word-break, eat it, and jump
  48.  * back to the end of the word.
  49.  * Returns TRUE on success, FALSE on errors.
  50.  */
  51. wrapword()
  52. {
  53.     register int cnt;            /* size of word wrapped to next line */
  54.     register int bp;            /* index to wrap on */
  55.     register int first = -1;
  56.     register int i;
  57.  
  58.     if(curwp->w_doto <= 0)        /* no line to wrap? */
  59.       return(FALSE);
  60.  
  61.     for(bp = cnt = i = 0; cnt < llength(curwp->w_dotp) && !bp; cnt++, i++){
  62.     if(isspace((unsigned char) lgetc(curwp->w_dotp, cnt).c)){
  63.         first = 0;
  64.         if(lgetc(curwp->w_dotp, cnt).c == TAB)
  65.           while(i+1 & 0x07)
  66.         i++;
  67.     }
  68.     else if(!first)
  69.       first = cnt;
  70.  
  71.     if(first > 0 && i >= fillcol)
  72.       bp = first;
  73.     }
  74.  
  75.     if(!bp)
  76.       return(FALSE);
  77.  
  78.     /* bp now points to the first character of the next line */
  79.     cnt = curwp->w_doto - bp;
  80.     curwp->w_doto = bp;
  81.  
  82.     if(!lnewline())            /* break the line */
  83.       return(FALSE);
  84.  
  85.     /* clean up trailing whitespace from line above ... */
  86.     if(backchar(FALSE, 1)){
  87.     while(llength(curwp->w_dotp) > 0 && backchar(FALSE, 1)
  88.           && isspace((unsigned char) lgetc(curwp->w_dotp, curwp->w_doto).c)
  89.           && (cnt > 0 || cnt < -1)){
  90.         forwdel(FALSE, 1);
  91.         if(cnt < 0)
  92.           ++cnt;
  93.     }
  94.  
  95.     gotoeol(FALSE, 1);
  96.     forwchar(FALSE, 1);        /* goto first char of next line */
  97.     }
  98.  
  99.     /*
  100.      * if there's a line below, it doesn't start with whitespace 
  101.      * and there's room for this line...
  102.      */
  103.     if(!(curbp->b_flag & BFWRAPOPEN)
  104.        && lforw(curwp->w_dotp) != curbp->b_linep 
  105.        && llength(lforw(curwp->w_dotp)) 
  106.        && !isspace((unsigned char) lgetc(lforw(curwp->w_dotp), 0).c)
  107.        && (llength(curwp->w_dotp) + llength(lforw(curwp->w_dotp)) < fillcol)){
  108.     gotoeol(0, 1);            /* then pull text up from below */
  109.     if(lgetc(curwp->w_dotp, curwp->w_doto - 1).c != ' ')
  110.       linsert(1, ' ');
  111.  
  112.     forwdel(0, 1);
  113.     gotobol(0, 1);
  114.     }
  115.  
  116.     curbp->b_flag &= ~BFWRAPOPEN;    /* don't open new line next wrap */
  117.                     /* restore dot (account for NL)  */
  118.     if(cnt && !forwchar(0, cnt < 0 ? cnt-1 : cnt))
  119.       return(FALSE);
  120.  
  121.     return(TRUE);
  122. }
  123.  
  124.  
  125. /*
  126.  * Move the cursor backward by "n" words. All of the details of motion are
  127.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  128.  * move beyond the buffers.
  129.  */
  130. backword(f, n)
  131. {
  132.         if (n < 0)
  133.                 return (forwword(f, -n));
  134.         if (backchar(FALSE, 1) == FALSE)
  135.                 return (FALSE);
  136.         while (n--) {
  137.                 while (inword() == FALSE) {
  138.                         if (backchar(FALSE, 1) == FALSE)
  139.                                 return (FALSE);
  140.                 }
  141.                 while (inword() != FALSE) {
  142.                         if (backchar(FALSE, 1) == FALSE)
  143.                                 return (FALSE);
  144.                 }
  145.         }
  146.         return (forwchar(FALSE, 1));
  147. }
  148.  
  149. /*
  150.  * Move the cursor forward by the specified number of words. All of the motion
  151.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  152.  */
  153. forwword(f, n)
  154. {
  155.         if (n < 0)
  156.                 return (backword(f, -n));
  157.         while (n--) {
  158. #if    NFWORD
  159.                 while (inword() != FALSE) {
  160.                         if (forwchar(FALSE, 1) == FALSE)
  161.                                 return (FALSE);
  162.                 }
  163. #endif
  164.                 while (inword() == FALSE) {
  165.                         if (forwchar(FALSE, 1) == FALSE)
  166.                                 return (FALSE);
  167.                 }
  168. #if    NFWORD == 0
  169.                 while (inword() != FALSE) {
  170.                         if (forwchar(FALSE, 1) == FALSE)
  171.                                 return (FALSE);
  172.                 }
  173. #endif
  174.         }
  175.     return(TRUE);
  176. }
  177.  
  178. #ifdef    MAYBELATER
  179. /*
  180.  * Move the cursor forward by the specified number of words. As you move,
  181.  * convert any characters to upper case. Error if you try and move beyond the
  182.  * end of the buffer. Bound to "M-U".
  183.  */
  184. upperword(f, n)
  185. {
  186.         register int    c;
  187.     CELL            ac;
  188.  
  189.     ac.a = 0;
  190.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  191.         return(rdonly());    /* we are in read only mode    */
  192.         if (n < 0)
  193.                 return (FALSE);
  194.         while (n--) {
  195.                 while (inword() == FALSE) {
  196.                         if (forwchar(FALSE, 1) == FALSE)
  197.                                 return (FALSE);
  198.                 }
  199.                 while (inword() != FALSE) {
  200.                         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  201.                         if (c>='a' && c<='z') {
  202.                                 ac.c = (c -= 'a'-'A');
  203.                                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  204.                                 lchange(WFHARD);
  205.                         }
  206.                         if (forwchar(FALSE, 1) == FALSE)
  207.                                 return (FALSE);
  208.                 }
  209.         }
  210.         return (TRUE);
  211. }
  212.  
  213. /*
  214.  * Move the cursor forward by the specified number of words. As you move
  215.  * convert characters to lower case. Error if you try and move over the end of
  216.  * the buffer. Bound to "M-L".
  217.  */
  218. lowerword(f, n)
  219. {
  220.         register int    c;
  221.     CELL            ac;
  222.  
  223.     ac.a = 0;
  224.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  225.         return(rdonly());    /* we are in read only mode    */
  226.         if (n < 0)
  227.                 return (FALSE);
  228.         while (n--) {
  229.                 while (inword() == FALSE) {
  230.                         if (forwchar(FALSE, 1) == FALSE)
  231.                                 return (FALSE);
  232.                 }
  233.                 while (inword() != FALSE) {
  234.                         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  235.                         if (c>='A' && c<='Z') {
  236.                                 ac.c (c += 'a'-'A');
  237.                                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  238.                                 lchange(WFHARD);
  239.                         }
  240.                         if (forwchar(FALSE, 1) == FALSE)
  241.                                 return (FALSE);
  242.                 }
  243.         }
  244.         return (TRUE);
  245. }
  246.  
  247. /*
  248.  * Move the cursor forward by the specified number of words. As you move
  249.  * convert the first character of the word to upper case, and subsequent
  250.  * characters to lower case. Error if you try and move past the end of the
  251.  * buffer. Bound to "M-C".
  252.  */
  253. capword(f, n)
  254. {
  255.         register int    c;
  256.     CELL            ac;
  257.  
  258.     ac.a = 0;
  259.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  260.         return(rdonly());    /* we are in read only mode    */
  261.         if (n < 0)
  262.                 return (FALSE);
  263.         while (n--) {
  264.                 while (inword() == FALSE) {
  265.                         if (forwchar(FALSE, 1) == FALSE)
  266.                                 return (FALSE);
  267.                 }
  268.                 if (inword() != FALSE) {
  269.                         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  270.                         if (c>='a' && c<='z') {
  271.                 ac.c = (c -= 'a'-'A');
  272.                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  273.                 lchange(WFHARD);
  274.                         }
  275.                         if (forwchar(FALSE, 1) == FALSE)
  276.                                 return (FALSE);
  277.                         while (inword() != FALSE) {
  278.                                 c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  279.                                 if (c>='A' && c<='Z') {
  280.                     ac.c = (c += 'a'-'A');
  281.                     lputc(curwp->w_dotp, curwp->w_doto, ac);
  282.                     lchange(WFHARD);
  283.                                 }
  284.                                 if (forwchar(FALSE, 1) == FALSE)
  285.                                         return (FALSE);
  286.                         }
  287.                 }
  288.         }
  289.         return (TRUE);
  290. }
  291.  
  292. /*
  293.  * Kill forward by "n" words. Remember the location of dot. Move forward by
  294.  * the right number of words. Put dot back where it was and issue the kill
  295.  * command for the right number of characters. Bound to "M-D".
  296.  */
  297. delfword(f, n)
  298. {
  299.         register long   size;
  300.         register LINE   *dotp;
  301.         register int    doto;
  302.  
  303.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  304.         return(rdonly());    /* we are in read only mode    */
  305.         if (n < 0)
  306.                 return (FALSE);
  307.         dotp = curwp->w_dotp;
  308.         doto = curwp->w_doto;
  309.         size = 0L;
  310.         while (n--) {
  311. #if    NFWORD
  312.         while (inword() != FALSE) {
  313.             if (forwchar(FALSE,1) == FALSE)
  314.                 return(FALSE);
  315.             ++size;
  316.         }
  317. #endif
  318.                 while (inword() == FALSE) {
  319.                         if (forwchar(FALSE, 1) == FALSE)
  320.                                 return (FALSE);
  321.                         ++size;
  322.                 }
  323. #if    NFWORD == 0
  324.                 while (inword() != FALSE) {
  325.                         if (forwchar(FALSE, 1) == FALSE)
  326.                                 return (FALSE);
  327.                         ++size;
  328.                 }
  329. #endif
  330.         }
  331.         curwp->w_dotp = dotp;
  332.         curwp->w_doto = doto;
  333.         return (ldelete(size, TRUE));
  334. }
  335.  
  336. /*
  337.  * Kill backwards by "n" words. Move backwards by the desired number of words,
  338.  * counting the characters. When dot is finally moved to its resting place,
  339.  * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
  340.  */
  341. delbword(f, n)
  342. {
  343.         register long   size;
  344.  
  345.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  346.         return(rdonly());    /* we are in read only mode    */
  347.         if (n < 0)
  348.                 return (FALSE);
  349.         if (backchar(FALSE, 1) == FALSE)
  350.                 return (FALSE);
  351.         size = 0L;
  352.         while (n--) {
  353.                 while (inword() == FALSE) {
  354.                         if (backchar(FALSE, 1) == FALSE)
  355.                                 return (FALSE);
  356.                         ++size;
  357.                 }
  358.                 while (inword() != FALSE) {
  359.                         if (backchar(FALSE, 1) == FALSE)
  360.                                 return (FALSE);
  361.                         ++size;
  362.                 }
  363.         }
  364.         if (forwchar(FALSE, 1) == FALSE)
  365.                 return (FALSE);
  366.         return (ldelete(size, TRUE));
  367. }
  368. #endif    /* MAYBELATER */
  369.  
  370. /*
  371.  * Return TRUE if the character at dot is a character that is considered to be
  372.  * part of a word. The word character list is hard coded. Should be setable.
  373.  */
  374. inword()
  375. {
  376.     return(curwp->w_doto < llength(curwp->w_dotp)
  377.        && isalnum((unsigned char)lgetc(curwp->w_dotp, curwp->w_doto).c));
  378. }
  379.  
  380.  
  381. /*
  382.  * Return TRUE if whatever starts the line matches the quote string
  383.  */
  384. quote_match(q, l)
  385.     char *q;
  386.     LINE *l;
  387. {
  388.     register int i;
  389.  
  390.     for(i = 0; i <= llength(l) && q[i]; i++)
  391.       if(q[i] != lgetc(l, i).c)
  392.     return(0);
  393.  
  394.     return(1);
  395. }
  396.  
  397.  
  398. fillpara(f, n)    /* Fill the current paragraph according to the current
  399.            fill column                        */
  400.  
  401. int f, n;    /* deFault flag and Numeric argument */
  402.  
  403. {
  404.     register int c;            /* current char durring scan    */
  405.     register int wordlen;        /* length of current word    */
  406.     register int clength;        /* position on line during fill    */
  407.     register int i;            /* index during word copy    */
  408.     register int newlength;        /* tentative new line length    */
  409.     register int eopflag;        /* Are we at the End-Of-Paragraph? */
  410.     register int firstflag;        /* first word? (needs no space)    */
  411.     register LINE *eopline;        /* pointer to line just past EOP */
  412.     register int dotflag;        /* was the last char a period?    */
  413.     char wbuf[NSTRING];            /* buffer for current word    */
  414.     int  first_word_of_paragraph;
  415.     int  end_of_input_line;
  416.     char *quote = NULL;
  417.     int   quote_len;
  418.     LINE *bqline, *eqline, *qline, *lp;
  419.  
  420.     if(curbp->b_mode&MDVIEW){        /* don't allow this command if    */
  421.     return(rdonly());        /* we are in read only mode    */
  422.     }
  423.     else if (fillcol == 0) {        /* no fill column set */
  424.     mlwrite("No fill column set");
  425.     return(FALSE);
  426.     }
  427.  
  428.     qline = curwp->w_dotp;        /* remember where we started */
  429.  
  430.     /* record the pointer to the line just past the EOP */
  431.     if(gotoeop(FALSE, 1) == FALSE)
  432.       return(FALSE);
  433.  
  434.     eopline = lforw(curwp->w_dotp);
  435.  
  436.     /* and back to the beginning of the paragraph */
  437.     gotobop(FALSE, 1);
  438.  
  439.     /* if we're the composer, and we were given a quoting string,
  440.      * and it starts the line we're on, do some special magic...
  441.      */
  442.     if(Pmaster && Pmaster->quote_str
  443.        && (quote_len = i = strlen(Pmaster->quote_str))
  444.        && i <= llength(curwp->w_dotp)){
  445.     while(--i >= 0 && Pmaster->quote_str[i] == lgetc(curwp->w_dotp, i).c)
  446.       ;
  447.  
  448.     if(i < 0){                /* bingo! */
  449. #ifdef    MAYBELATER
  450.         switch(mlyesno("Format quoted text", TRUE)){
  451.           case FALSE :
  452.         gotoeop(FALSE, 1);
  453.         forwchar(FALSE, 1);
  454.           case ABORT :
  455.         emlwrite("Text not Justified", NULL);
  456.         return(TRUE);
  457.  
  458.           default :
  459.         emlwrite("Justifying quoted text", NULL);
  460.         }
  461. #endif
  462.  
  463.         /*
  464.          * adjust fillcol and bracket the quoted text with special
  465.          * blank lines
  466.          */
  467.         quote = Pmaster->quote_str;
  468.         fillcol -= quote_len;
  469.  
  470.         i = curwp->w_doto;
  471.         gotobol(FALSE, 1);
  472.         lnewline();                /* insert special blank line */
  473.         backchar(FALSE, 1);            /* back onto it */
  474.         bqline = curwp->w_dotp;        /* mark start of quoted text */
  475.         curwp->w_dotp = eopline;
  476.         gotoeol(FALSE, 1);
  477.         lnewline();
  478.         eqline = curwp->w_dotp;        /* mark end of quoted text */
  479.         curwp->w_dotp = lforw(bqline);    /* restore dot */
  480.         curwp->w_doto = i;
  481.     }
  482.     }
  483.  
  484.     /* let yank() know that it may be restoring a paragraph */
  485.     thisflag |= CFFILL;
  486.     
  487.     if(Pmaster == NULL)
  488.       sgarbk = TRUE;
  489.     
  490.     curwp->w_flag |= WFMODE;
  491.  
  492.     /* save text to be justified to the cut buffer */
  493.     fdelete();
  494.     for(lp = curwp->w_dotp;
  495.     lp != curbp->b_linep && lp != eopline;
  496.     lp = lforw(lp)){
  497.     for(i=(lp == curwp->w_dotp) ? curwp->w_doto : 0; i < llength(lp); i++)
  498.       finsert(lgetc(lp, i).c);
  499.  
  500.     finsert('\n');
  501.     }
  502.  
  503.     if(quote){
  504.     /* remove quoting from whole shebang */
  505.     curwp->w_dotp = lforw(bqline);
  506.     curwp->w_doto = 0;
  507.     do
  508.       if(quote_match(quote, curwp->w_dotp))
  509.         forwdel(FALSE, (quote_len > llength(curwp->w_dotp))
  510.                  ? llength(curwp->w_dotp) : quote_len);
  511.     while((curwp->w_dotp = lforw(curwp->w_dotp)) != lback(eqline));
  512.  
  513.     /* got to the line we started on */
  514.     curwp->w_dotp = qline;
  515.     curwp->w_doto = 0;
  516.     gotoeop(FALSE, 1);
  517.     eopline = lforw(curwp->w_dotp);    /* eop within quoted text */
  518.     /* make sure new eop isn't beyond special token line */
  519.     for(lp = curwp->w_dotp;
  520.         lp != curbp->b_linep && lp != lback(eqline);
  521.         lp = lforw(lp))
  522.       ;
  523.  
  524.     /* no quoted text to justify, just clean up and return */
  525.     if(lp == curbp->b_linep){
  526.         fillcol += quote_len;    /* restore fillcol */
  527.         curwp->w_dotp = bqline;    /* blast leading special blank line */
  528.         gotobol(FALSE, 1);
  529.         forwdel(FALSE, 1);
  530.         do{                /* restore quoting */
  531.         curwp->w_doto = 0;
  532.         for(i = 0; i < quote_len; i++)
  533.           linsert(1, quote[i]);
  534.         }
  535.         while((curwp->w_dotp = lforw(curwp->w_dotp)) != lback(eqline));
  536.         curwp->w_dotp = lback(eqline);
  537.         gotoeol(FALSE, 1);
  538.         forwdel(FALSE, 1);        /* blast trailing special blank line */
  539.         gotobol(FALSE, 1);
  540.         fdelete();            /* blast pre-justify text */
  541.         return(TRUE);
  542.     }
  543.  
  544.     curwp->w_dotp = lback(eopline);
  545.     curwp->w_doto = 0;
  546.     gotobop(FALSE, 1);
  547.     }
  548.     
  549.     /* initialize various info */
  550.     clength = curwp->w_doto;
  551.     if (clength && curwp->w_dotp->l_text[0].c == TAB)
  552.       clength = 8;
  553.     wordlen = 0;
  554.     dotflag = FALSE;
  555.     
  556.     /* scan through lines, filling words */
  557.     firstflag = TRUE;
  558.     eopflag = FALSE;
  559.     first_word_of_paragraph = TRUE;
  560.     
  561.     while (!eopflag) {
  562.     /* get the next character in the paragraph */
  563.     if (curwp->w_doto == llength(curwp->w_dotp)) {
  564.         c = ' ';
  565.         end_of_input_line = TRUE;
  566.         if (lforw(curwp->w_dotp) == eopline)
  567.           eopflag = TRUE;
  568.     }
  569.     else{
  570.         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  571.         end_of_input_line = FALSE;
  572.     }
  573.  
  574.     /* and then delete it */
  575.     ldelete(1L, FALSE);
  576.  
  577.     /* if not a separator, just add it in */
  578.     if (c != ' ' && c != TAB) {
  579.         /* 
  580.          * don't want to limit ourselves to only '.'
  581.          */
  582.         dotflag = (int)strchr(".?!:;\")", c); /* dot ? */
  583.         if (wordlen < NSTRING - 1)
  584.           wbuf[wordlen++] = c;
  585.     } else if (wordlen) {
  586.         /* at a word break with a word waiting */
  587.         /* calculate tentitive new length with word added */
  588.         newlength = clength + 1 + wordlen;
  589.         if (newlength <= fillcol) {
  590.         /* add word to current line */
  591.         if (!firstflag) {
  592.             linsert(1, ' ');    /* the space */
  593.             ++clength;
  594.         }
  595.         firstflag = FALSE;
  596.         } else {
  597.         /* start a new line */
  598.         if(!first_word_of_paragraph)
  599.           lnewline();
  600.         clength = 0;
  601.         }
  602.  
  603.         first_word_of_paragraph = FALSE;
  604.  
  605.         /* and add the word in in either case */
  606.         for (i=0; i<wordlen; i++) {
  607.         linsert(1, wbuf[i]);
  608.         ++clength;
  609.         }
  610.  
  611.         /*  Strategy:  Handle 3 cases:
  612.          *     1. if . at end of line put extra space after it
  613.          *     2. if . and only 1 space, leave only one space 
  614.          *     3. if . and more than 1 space, leave 2 spaces
  615.          *
  616.          *  So, we know the current c is a space. if then 
  617.          *  is no next c or the next c is a ' ' then we 
  618.          *  need to insert a space else don't do it.
  619.          */
  620.         if(dotflag && (end_of_input_line
  621.                || (' ' == lgetc(curwp->w_dotp, curwp->w_doto).c))){
  622.         linsert(1, ' ');
  623.         ++clength;
  624.         }
  625.  
  626.         wordlen = 0;
  627.     }
  628.     }
  629.     
  630.     /* and add a last newline for the end of our new paragraph */
  631.     lnewline();
  632.     
  633.     if(quote){                /* replace quoting strings */
  634.     fillcol += quote_len;
  635.     /* remember the current dot. note: ldelete at eob special, handle it */
  636.     eopline = (lforw(curwp->w_dotp) == curbp->b_linep)
  637.              ? curbp->b_linep : curwp->w_dotp;
  638.     curwp->w_dotp = bqline;
  639.     forwdel(FALSE, 1);        /* blast special blank line */
  640.     do{
  641.         curwp->w_doto = 0;        /* fill quote strings back in */
  642.         for(i = 0; i < quote_len; i++)
  643.           linsert(1, quote[i]);
  644.     }
  645.     while((curwp->w_dotp = lforw(curwp->w_dotp)) != lback(eqline));
  646.  
  647.     curwp->w_dotp = lback(eqline);    /* blast ending special blank line */
  648.     gotobol(FALSE, 1);
  649.     forwdel(FALSE, 1);
  650.  
  651.     /*
  652.      * Restore cursor to eop w/in quote.  Note special handling 
  653.      * when end of quoted text and end of buffer are the same...
  654.      */
  655.     curwp->w_dotp = eopline;
  656.     curwp->w_doto = (quote_len > llength(curwp->w_dotp)) ? 0 : quote_len;
  657.     }
  658. }
  659.